package logobj.utils;

import logobj.entity.bak.LogFileInFo;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;

public class BigFileUtils implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 快速切割文件2
     * */
    public void fileFastCopy2(String sourcePath, String destPath,long startsize,long size){
        try {
            RandomAccessFile reader = new RandomAccessFile(sourcePath, "r");
            FileChannel channel = reader.getChannel();
           // ByteArrayOutputStream out = new ByteArrayOutputStream();
            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,startsize,size);
            if(buffer.hasRemaining()){
                byte[] data = new byte[buffer.remaining()];
                buffer.get(data);
                BinaryFileUtils.writeByteToText(destPath,data);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 快速切割文件
     * */
    public  void fileFastCopy(String sourcePath, String destPath,long startsize,long size){
        File source = null;
        File dest = null;
        MappedByteBuffer mappedByteBuffer = null;
        source = new File(sourcePath);
        dest = new File(destPath);
        if(dest.exists()){
            dest.delete();
        }
        try {
            FileChannel fileChannelIn = new FileInputStream(source).getChannel();
            FileChannel fileChannelout = new FileOutputStream(dest).getChannel();
            //size = fileChannelIn.size();
            mappedByteBuffer = fileChannelIn.map(FileChannel.MapMode.READ_ONLY,startsize,size);
            fileChannelout.write(mappedByteBuffer);
            mappedByteBuffer.force();
            fileChannelIn.close();
            clean(mappedByteBuffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void clean(final MappedByteBuffer buffer)  {
        if(buffer == null){
            return;
        }
        buffer.force();
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                try {
                    Method getCleanerMethod = buffer.getClass().getMethod("cleaner",new Class[0]);
                    getCleanerMethod.setAccessible(true);
                    sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod.invoke(buffer,new Object[0]);
                    if(null != cleaner){
                        cleaner.clean();
                    }
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }
    /**
     * 删除目录文件
     * */
    public  boolean deleteDir(String path){
        File file = new File(path);
        if(!file.exists()){//判断是否待删除目录是否存在
            return false;
        }
        String[] content = file.list();//取得当前目录下所有文件和文件夹
        for(String name : content){
            File temp = new File(path, name);
            if(temp.isDirectory()){//判断是否是目录
                deleteDir(temp.getAbsolutePath());//递归调用，删除目录里的内容
                temp.delete();//删除空目录
            }else{
                if(!temp.delete()){//直接删除文件
                    System.err.println("Failed to delete " + name);
                }
            }
        }
        return true;
    }

    /**
     * 建立文件索引
     * **/
    public LogFileInFo createIndex(String textfilename, String binfilename){
        LogFileInFo logFileInFo = new LogFileInFo();
        long allLines = 0;
        long filesize = 0;
        byte[] linebytearr = null;
        FileInputStream inputStream = null;
        Scanner sc = null;
        String line = null;
        ArrayList TextByteArrList = new ArrayList<>();
        try{
            inputStream = new FileInputStream(textfilename);
            sc = new Scanner(inputStream, "UTF-8");
            while(sc.hasNextLine()) {
                line = sc.nextLine();
                int size = line.getBytes().length + 1;
                filesize += size;
                linebytearr = ByteTransform.InTo2ByteArr(size);
                TextByteArrList.add(linebytearr[0]);
                TextByteArrList.add(linebytearr[1]);
                allLines ++;
            }
            if(sc.ioException() != null) {
                throw sc.ioException();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sc != null) {
                sc.close();
            }
        }
        int row =  TextByteArrList.size();
        byte[] TextByteArr = new byte[row];
        for(int i=0 ; i< row ; i+=2){
            TextByteArr[i] = (byte)TextByteArrList.get(i);
            TextByteArr[i + 1] = (byte)TextByteArrList.get(i+1);
        }
        logFileInFo.setFilename(textfilename);
        logFileInFo.setIndexname(binfilename);
        logFileInFo.setFilerownum(allLines);
        logFileInFo.setFilesize(filesize);
        //写入二进制文件
        BinaryFileUtils.writeByteToText(binfilename,TextByteArr);
        return logFileInFo;
    }
    /**
     * 获取范围行数内在文本的字节值
     * */
    public long[] getTextSizePoit(String binfilename,int startnum, int endnum){
        long[] poit = new long[2];
        BigFileUtils fileUtils = new BigFileUtils();
        byte[] binbytearr = BinaryFileUtils.readByteFromText(binfilename);
        long num = 0 ;
        int numByteInt = 0;
        byte[] poitbyte = new byte[2];
        for (int i= 0 ; i< binbytearr.length ; i += 2){
            poitbyte[0] = binbytearr[i];
            poitbyte[1] = binbytearr[i + 1];
            numByteInt = ByteTransform.ByteArrToInt(poitbyte);
            num += (long)numByteInt;
            if( ((startnum - 1 ) * 2 )== (i + 2) ){
                poit[0] = num;
            }
            if( ((endnum - 1) * 2 )== (i + 2)){
                poit[1] = num;
                break;
            }
        }
        return poit;
    }

    /**
     * 根据文件路径获取文件信息
     * */
    public Map<String, ArrayList> getFileInfo(String path){
        Map<String, ArrayList> fileinfo = new HashMap<>();
        ArrayList namelist = new ArrayList();
        ArrayList sizelist = new ArrayList();
        File filedir = new File(path);
        File[] filelist = filedir.listFiles();
        FileInputStream fis= null;
        FileChannel fc= null;
        for(File file : filelist){
            if(file.isFile()){
                namelist.add(file.getName());
                try {
                    fis= new FileInputStream(file);
                    fc= fis.getChannel();
                    sizelist.add(fc.size());
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        fileinfo.put("namelist",namelist);
        fileinfo.put("sizelist",sizelist);
        return fileinfo;
    }

    /**
     * 深度遍历，获取目录下的所有文件
     * */
    public ArrayList<String> getFileList(String path, String findmodel){
        ArrayList<String> filepathlist = new ArrayList<>();
        File fileDir = new File(path);
        File[] files = null;
        if(fileDir.isDirectory()){
            files = fileDir.listFiles();
            for(File fi : files){
                if(fi.isDirectory()){
                    if("all".equals(findmodel)){
                        filepathlist.addAll(getFileList(fi.getAbsolutePath(),findmodel)) ;
                    }
                }else {
                    filepathlist.add(fi.getAbsolutePath());
                }
            }
        }else{
            filepathlist.add(fileDir.getAbsolutePath());
        }
        return filepathlist;
    }

    /***
     * 获取文本文件行数
     * */
    public long getFastFileConut(String filePath){
        File file = new File(filePath);
        if(file.isFile()){
            try {
                return Files.lines(Paths.get(filePath)).count();
            } catch (IOException e) {
                return -1;
            }
        }
        return -1;
    }

    public  TreeMap<Long,Long> createIndexTree(String textfilename){
        FileInputStream inputStream = null;
        Scanner sc = null;
        String linestr = null;
        long filesize = 0;
        long fileline = 0;
        TreeMap<Long,Long> idxmap  = new TreeMap<>();
        try{
            inputStream = new FileInputStream(textfilename);
            sc = new Scanner(inputStream, "UTF-8");
            while(sc.hasNextLine()) {
                linestr = sc.nextLine();
                filesize += linestr.getBytes().length + 1;
                fileline +=1;
                idxmap.put(fileline,filesize);
            }
            if(sc.ioException() != null) {
                throw sc.ioException();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sc != null) {
                sc.close();
            }
        }
        return idxmap;
    }

    /***
     * 序列化索引对象
     * */
    public void witreIdx(TreeMap<Long,Long> idx , String idxPath){
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(idxPath));
            objectOutputStream.writeObject(idx);
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /***
     * 获取索引对象
     * */
    public TreeMap<Long,Long> readIdx(String idxPath){
        TreeMap<Long,Long> idx = null;
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(idxPath));
            idx = ( TreeMap<Long,Long>)objectInputStream.readObject();
            objectInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return idx;
    }
}
